package com.qf.controller;

import com.qf.captcha.CaptchaCodeManager;
import com.qf.pojo.DtsAdmin;
import com.qf.service.AdminService;
import com.qf.service.RoleService;
import com.qf.service.impl.PermsService;
import com.qf.util.Base64;
import com.qf.util.UUID;
import com.qf.util.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 后台管理之 验证码、登录 认证
 *
 * @author lixu
 */
@CrossOrigin
@RestController
@RequestMapping("/admin/auth")
public class AdminAuthController {


    @Autowired
    private AdminService adminService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermsService permsService;
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 获取验证码
     * - 生成验证码请求地址 : http://localhost:8083/admin/auth/captchaImage
     * - GET请求
     * - 下行数据 :
     * - uuid : 图片id(服务器端将图片保存在shiro的会话中的唯一id),  img : 图片地址
     */
    //@RequestMapping(value = "/",method = RequestMethod.GET)
    @GetMapping("/captchaImage")
    public Object captchaImage() throws Exception {

        //1:uuid 真实数据   36还有-线
        String uuid = UUID.randomUUID().toString();
        //2:获取下面的 img的真实数据 验证码
        //2.1: 生成4567 数
        String code = VerifyCodeUtils.generateVerifyCode(4);
        //2.2 将四数保存到缓存中
        CaptchaCodeManager.addToCache(uuid, code, null);//默认是3分钟
        //2.2 将数转成图片的二进制 //转成Base64
        ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
        //执行
        VerifyCodeUtils.outputImage(100, 36, byteOutputStream, code);
        //sessionID:uuid   Session对象
        //Session对象.getAttribute("code","1234")
        //浏览器有Cookie Vue不用Cookie
        //返回值 准备出下行数据
        Map map = new HashMap();
        map.put("uuid", uuid);
        map.put("img", Base64.encode(byteOutputStream.toByteArray()));
        return ResponseUtil.ok(map);
    }

    /**
     * - 登录请求地址 : http://localhost:8083/admin/auth/login
     * - POST请求
     * - 上行数据:
     * {
     * "code": "66e8",
     * "password": "123456",
     * "username": "qianfeng",
     * "uuid": "cab317c6-1bf1-436d-96ac-fda9f8d37dde"
     * }
     */
    @PostMapping("/login")
    public Object login(@RequestBody String adminJson) {
        String username = JacksonUtil.parseString(adminJson, "username");
        String password = JacksonUtil.parseString(adminJson, "password");
        String code = JacksonUtil.parseString(adminJson, "code");
        String uuid = JacksonUtil.parseString(adminJson, "uuid");

        //1:校验验证码
/*        if(StringUtils.isEmpty(code)){
            return ResponseUtil.fail(-1,"验证码不能为空");
        }
        String c = CaptchaCodeManager.getCachedCaptcha(uuid);
        if(StringUtils.isEmpty(c)){
            return ResponseUtil.fail(-1,"验证码已经过期");
        }
        if(!code.equalsIgnoreCase(c)){
            return ResponseUtil.fail(-1,"验证码不正确");
        }*/
        //2:校验用户名及密码不能为空
        if (StringUtils.isEmpty(username)) {
            return ResponseUtil.fail(-1, "用户名不能为空");
        }
        if (StringUtils.isEmpty(password)) {
            return ResponseUtil.fail(-1, "密码不能为空");
        }
        //3:校验用户名及密码必须正确
        //安全框架 Shiro  整合Shiro
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken =
                new UsernamePasswordToken(username, password);
        try {
            subject.login(usernamePasswordToken);
        } catch (AuthenticationException e) {
            return ResponseUtil.fail(-1, e.getMessage());
        }
        Session session = subject.getSession();
        return ResponseUtil.ok(session.getId());

    }

    /**
     * {
     * RBAC模式：
     * 5张表：
     * <p>
     * "errno":0,
     * "data":{
     * "roles":["超级管理员","开发工程师","财务人员"],
     * "name":"qianfeng",
     * "perms":["*"],     * 代表超级管理员 所有权限
     * "avatar":"https://dss1.bdstatic.com/6OF1,499686101&fm=85&app=79&f=JPEG?w=121&h=75&s=81B24C32D40"
     * },
     * "errmsg":"成功"
     * }
     */
    //@RequiresUser //要求必须登录才能访问
    @GetMapping("/info")
    public Object info(HttpServletRequest request) {
        Subject subject = SecurityUtils.getSubject();
        DtsAdmin dtsAdmin = (DtsAdmin) subject.getPrincipal();

        //角色集合
        Set<String> roles = roleService.findRolesByRoleIds(dtsAdmin.getRoleIds());
        //权限集合
        Set<String> perms = permsService.findPermsByRoleIds(dtsAdmin.getRoleIds());

        Map data = new HashMap();
        data.put("roles", roles);
        data.put("name", dtsAdmin.getUsername());
        // 后期： 数据库中的权限 替换成页面支持的权限
        data.put("perms", toApi(perms));

        data.put("avatar", dtsAdmin.getAvatar());//Logo

        return ResponseUtil.ok(data);

    }

    /**
     * //TODO 复杂处理
     * //TODO 最终转换成页面需要的权限
     * //TODO perms: ['GET /admin/brand/list', 'POST /admin/brand/create',
     * // TODO 'GET /admin/brand/read', 'POST /admin/brand/update', 'POST /admin/brand/delete'],
     * <p>
     * "admin:category:update",
     * "admin:category:list",
     * "admin:category:read",
     * "admin:category:delete",
     * "admin:category:create",
     * "admin:role:permission:update",
     * "admin:role:update",
     * "admin:role:list",
     * "admin:role:read",
     * "admin:role:delete",
     * "admin:role:permission:get",
     * "admin:role:create"
     * <p>
     * 权限转换
     * Java代码这边的权限转换成Vue页面那边的权限
     *
     * @param perms Java代码这边的权限
     * @return
     */
    public List<String> toApi(Set<String> perms) {//Set是当前用户拥有的权限
        //1:判断是否为NULL
        if (CollectionUtils.isEmpty(perms)) {
            return new ArrayList<>();//[]
        }
        //2: Set是当前用户拥有的权限  集合中只要有一个* 不要再判断了
        if (perms.contains("*")) {
            return Arrays.asList("*");
        }
        //3:不要是超级管理员
        String p = "com.qf.controller";
        //整个项目所有Controller了权限
        List<Permission> permissions = PermissionUtil.listPermission(applicationContext, p);
        //使用所有权限进行遍历 过滤出当前用户拥有的权限
        return permissions.stream().filter((permission) -> {
            if (perms.contains(permission.getRequiresPermissions().value()[0])) {
                return true;//留下了
            } else {
                return false;//不要了 过滤掉
            }
        }).map(Permission::getApi).collect(Collectors.toList());
    }

}
